import { VMUtil } from "./VMUtil";
import { Compile } from "./Compile";
import { IVMMain, IWatcher, ICompile, IVMOptions } from "../Interfaces/IMVVM";
import { VMFactory } from "./VMFactory";
import ADQ from "../Core/ADQ";
import { Observe } from "./Observe";
import { IDispose } from "../Interfaces/IGameManager";
import ResouceManager from "../Implements/ResouceManager";

/**
 * AD框架VM

 */
export default class ADVM implements IVMMain {
  $targetWatcher: IWatcher;
  $identity: number;
  $options: IVMOptions;
  $icompile: ICompile;
  $actions: any;
  $el: any;
  $isDestroy: boolean;
  $pools: Array<IDispose>; //资源池
  /**
   * 实例化VM组件
   * @param options 实列参数
   */
  constructor(options: IVMOptions) {
    /**必包含参数判定 */
    if (options.data && options.el) {
      this.$identity = VMFactory.getGloableId();
      this.$options = options;
      this.$el = options.el;
      this.scopeChange(this, options.actions);
      this.$actions = options.actions;
      this.createDestroyProxy();
      this.$pools = [];

      this.createProxyMethods(this.$options.methods);
      if (options.syncInit) {
        options.syncInit = options.syncInit.bind(this);
        options.syncInit(this.$el, this.$options.data, (that) => {
          this.init();
        });
      } else {
        this.init();
      }
    }
  }
  private init() {
    //数据监听前
    if (this.$options.beforeCreate)
      ADQ.runHandler(this, this.$options.beforeCreate, [
        this.$el,
        this.$options.data,
      ]);
    this.createObserve(this.$options.data, false);
    this.createObserve(this.$options.computed, true);
    this.createProxy(this.$options.components);

    //数据监听后
    if (this.$options.created)
      ADQ.runHandler(this, this.$options.created, [
        this.$el,
        this.$options.data,
      ]);
    this.$icompile = new Compile(this); //指令解析
    if (this.$options.mounted)
      ADQ.runHandler(this, this.$options.mounted, [
        this.$el,
        this.$options.data,
      ]);
  }
  /**this作用域修正 */
  private scopeChange(that, data) {
    for (var item in data) {
      data[item] = data[item].bind(that);
    }
  }
  /**创建销毁代理 */
  private createDestroyProxy() {
    var destroy = this.$el[VMUtil.instance.destroyName];
    if (destroy) {
      this.$el[VMUtil.instance.destroyName] = this.intercept(
        destroy.bind(this.$el),
        null,
        this.$destroy.bind(this)
      );
    }
  }
  /**局部函数拦截 */
  private intercept(
    orignFun: Function,
    before: Function,
    after: Function
  ): any {
    var fun = () => {
      if (before) before.apply(arguments);
      orignFun.apply(arguments);
      if (after) after.apply(arguments);
    };
    return fun;
  }
  /**
   * 构建数据监听
   * @param data 监听数据
   * @param isComputed 是否为计算属性
   */
  private createObserve(data: any, isComputed: boolean) {
    if (!data) return;
    this.createProxy(data);
    Observe.observe(data, this, isComputed); //数据劫持、监听数据变化
  }
  /**
   * 构建基础数据代理，无数据监听
   * @param data
   */
  private createProxy(data: any) {
    if (!data) return;
    var self = this;
    Object.keys(data).forEach((key) => {
      self.$proxyData(data, key);
    });
  }
  /**
   * 构建基础函数处理代理
   * @param data
   */
  private createProxyMethods(methods: any) {
    if (!methods) return;
    var self = this;
    Object.keys(methods).forEach((key) => {
      self[key] = methods[key];
    });
  }
  $set(target: IVMMain, key: any, val: any) {
    Observe.setData(target, key, val, this);
  }
  /**
   * 数据代理 将option 参数代理至this
   * @param key 代理关键词
   */
  $proxyData(dataSource: any, key: any) {
    var setter =
      setter ||
      Object.defineProperty(this, key, {
        configurable: true,
        enumerable: true,
        get: function proxyGetter() {
          return dataSource[key];
        },
        set: function proxySetter(newVal) {
          dataSource[key] = newVal;
        },
      });
  }

  /**
   * 数据代理 将空数据 参数代理至this
   * @param key 代理关键词
   */
  $proxyDataToTemp(key: any) {
    var setter =
      setter ||
      Object.defineProperty(this, key, {
        configurable: true,
        enumerable: true,
        get: function proxyGetter() {
          return null;
        },
        set: function proxySetter(newVal) {},
      });
  }
  $destroy() {
    if (this.$isDestroy) return;
    this.$isDestroy = true;
    if (this.$options)
      ADQ.runHandler(this, this.$options.beforeDestroy, [
        this.$el,
        this.$options.data,
      ]);
    //暂未实现
    var self = this;
    Object.keys(this.$options.data).forEach((key) => {
      self.$proxyDataToTemp(key);
    });
    //清空资源池
    while (this.$pools.length > 0) {
      const element = this.$pools.pop();
      element.dispose();
      ResouceManager.clearObject(element);
    }
    if (this.$options)
      ADQ.runHandler(this, this.$options.destroyed, [
        this.$el,
        this.$options.data,
      ]);
    ResouceManager.clearObjectToTemp(this);
  }
}
